/*
 * csvparse.h
 *
 *  Created on: 2015-11-21
 *      Author: BenWen
 */

#ifndef CSVREADER_H_
#define CSVREADER_H_

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>

using namespace std;

namespace csv {

    typedef vector<string> row;
    typedef vector<row> table;

	class parser {
		private:
			table _table;
			row _head;
			unsigned int get_column_index(const char *column_name);
			int get_string(const unsigned int row, const unsigned int col, char *value,const char *def=0);
			int get_integer(const unsigned int row, const unsigned int col, int *value,const int def=0);
			int get_double(const unsigned int row, const unsigned int col, double *value,const double def=0);
			int get_bool(const unsigned int row, const unsigned int col, bool *value,const int def=0);
		public:
			parser();
			~parser();
			int load(const char *csvfile);
			int get_row_count();
			int get_string_cell(const unsigned int row, const char *head, char *value,const char *def=0);
			int get_integer_cell(const unsigned int row, const char *head, int *value,const int def=0);
			int get_double_cell(const unsigned int row, const char *head, double *value,const double def=0);
			int get_bool_cell(const unsigned int row, const char *head,bool *value, const int def=0);
	};

	parser::parser() {

	}

	parser::~parser() {

	}

	int parser::load(const char *csvfile) {

		row _row;
		string _line;
		ifstream _file(csvfile);
		if (_file.fail()) {
			cout << "The following file was not found: " << csvfile << endl;
			return 0;
		}
		int counter = 0;
		_table.clear();
		while ( _file.good() ) {
			getline(_file, _line);
			if(_line.empty()) continue;
			cout<<_line<<endl;
			int _pos = 0;
			int _inquotes = false;
			char c;
			int _length = _line.length();
			string _cur_string;
			_row.clear();

			while (_line[_pos] != 0 && _pos < _length) {
				c = _line[_pos];
				if (!_inquotes && _cur_string.length() == 0 && c == '"') { //beginquotechar
					_inquotes = true;
				} else if (_inquotes && c == '"') { //quotechar
					if ((_pos + 1 < _length) && (_line[_pos + 1] == '"')) { //encountered 2 double quotes in a row (resolves to 1 double quote)
						_cur_string.push_back(c);
						_pos++;
					} else { //endquotechar
						_inquotes = false;
					}
				} else if (!_inquotes && c == ',') { //end of field
					_row.push_back(_cur_string);
					_cur_string = "";
				} else if (!_inquotes && (c == '\r' || c == '\n')) {
					break;
				} else {
					_cur_string.push_back(c);
				}
				_pos++;
			}
			_row.push_back(_cur_string);
			if (0 == counter)
				this->_head = _row;
			else
				_table.push_back(_row);
			counter++;
		}
		_file.close();
		return 0;
	}

	int parser::get_row_count() {
		return _table.size();
	}

	unsigned int parser::get_column_index(const char *headname) {
		for (unsigned int i = 0; i < _head.size(); i++) {
			if (strcmp(headname, _head.at(i).c_str()) == 0)
				return i + 1;
		}
		return 0;
	}

	int parser::get_string(const unsigned int row, const unsigned int col, char *value,const char *def) {
		if ((row >= 1) && (row <= _table.size())) {
			if ((col >= 1) && (col <= _table.at(row - 1).size())) {
				strcpy(value, _table.at(row - 1).at(col - 1).c_str());
				return 0;
			}
		}
		strcpy(value, def);
		return 1;
	}

	int parser::get_integer(const unsigned int row, const unsigned int col, int *value,const int def) {
		char _str[64];
		char _def[64];
		sprintf(_def, "%d", def);
		int _ret = get_string(row, col, _str, _def);
		*value = atoi(_str);
		return _ret;
	}

	int parser::get_double(const unsigned int row, const unsigned int col, double *value,const double def) {
		char _str[64];
		char _def[64];
		sprintf(_def, "%f", def);
		int _ret = get_string(row, col, _str, _def);
		*value = atof(_str);
		return _ret;
	}

	int parser::get_bool(const unsigned int row, const unsigned int col, bool *value,const int def) {
		char _str[64];
		char _def[64];
		sprintf(_def, "%d", def);
		int _ret = get_string(row, col, _str, _def);
		*value = (bool) atoi(_str);
		return _ret;
	}

	int parser::get_string_cell(const unsigned int row, const char *head, char *value, const char *def) {
		unsigned int col = get_column_index(head);
		return get_string(row, col, value, def);
	}
	int parser::get_integer_cell(const unsigned int row, const char *head, int *value, const int def) {
		unsigned int col = get_column_index(head);
		return get_integer(row, col, value, def);
	}
	int parser::get_double_cell(const unsigned int row, const char *head, double *value, const double def) {
		unsigned int col = get_column_index(head);
		return get_double(row, col, value, def);
	}
	int parser::get_bool_cell(const unsigned int row, const char *head, bool *value, const int def) {
		unsigned int col = get_column_index(head);
		return get_bool(row, col, value, def);
	}
}

#endif /* CSVREADER_H_ */